﻿#include "LockBitmap.h"

namespace Server::MirForms::VisualMapInfo::Class
{

    std::vector<unsigned char> LockBitmap::getPixels() const
    {
        return Pixels;
    }

    void LockBitmap::setPixels(const std::vector<unsigned char> &value)
    {
        Pixels = value;
    }

    int LockBitmap::getDepth() const
    {
        return Depth;
    }

    void LockBitmap::setDepth(int value)
    {
        Depth = value;
    }

    int LockBitmap::getWidth() const
    {
        return Width;
    }

    void LockBitmap::setWidth(int value)
    {
        Width = value;
    }

    int LockBitmap::getHeight() const
    {
        return Height;
    }

    void LockBitmap::setHeight(int value)
    {
        Height = value;
    }

    LockBitmap::LockBitmap(Bitmap *source)
    {
        this->source = source;
    }

    void LockBitmap::LockBits()
    {
        try
        {
            setWidth(source->Width);
            setHeight(source->Height);

            int PixelCount = getWidth() * getHeight();

            Rectangle *rect = new Rectangle(0, 0, getWidth(), getHeight());

            setDepth(System::Drawing::Bitmap::GetPixelFormatSize(source->PixelFormat));

            if (getDepth() != 8 && getDepth() != 24 && getDepth() != 32)
            {
                delete rect;
                throw std::invalid_argument("Only 8, 24 and 32 bpp images are supported.");
            }

            bitmapData = source->LockBits(rect, ImageLockMode::ReadWrite, source->PixelFormat);

            int step = getDepth() / 8;
            setPixels(std::vector<unsigned char>(PixelCount * step));
            Iptr = bitmapData->Scan0;

            Marshal::Copy(Iptr, getPixels(), 0, getPixels().size());

//C# TO C++ CONVERTER TODO TASK: A 'delete rect' statement was not added since rect was passed to a method or constructor. Handle memory management manually.
        }
        catch (const std::runtime_error &ex)
        {
            throw ex;
        }
    }

    void LockBitmap::UnlockBits()
    {
        try
        {
            Marshal::Copy(getPixels(), 0, Iptr, getPixels().size());

            source->UnlockBits(bitmapData);
        }
        catch (const std::runtime_error &ex)
        {
            throw ex;
        }
    }

    Color *LockBitmap::GetPixel(int x, int y)
    {
        Color *clr = Color::Empty;

        int cCount = getDepth() / 8;

        int i = ((y * getWidth()) + x) * cCount;

        if (i > getPixels().size() - cCount)
        {
//C# TO C++ CONVERTER TODO TASK: This exception's constructor requires an argument:
//ORIGINAL LINE: throw new IndexOutOfRangeException();
            throw std::out_of_range();
        }

        if (getDepth() == 32)
        {
            unsigned char b = getPixels()[i];
            unsigned char g = getPixels()[i + 1];
            unsigned char r = getPixels()[i + 2];
            unsigned char a = getPixels()[i + 3]; // a
            clr = Color::FromArgb(a, r, g, b);
        }
        if (getDepth() == 24)
        {
            unsigned char b = getPixels()[i];
            unsigned char g = getPixels()[i + 1];
            unsigned char r = getPixels()[i + 2];
            clr = Color::FromArgb(r, g, b);
        }
        if (getDepth() == 8)
        {
            unsigned char c = getPixels()[i];
            clr = Color::FromArgb(c, c, c);
        }
        return clr;
    }

    void LockBitmap::SetPixel(int x, int y, Color *color)
    {
        int cCount = getDepth() / 8;

        int i = ((y * getWidth()) + x) * cCount;

        if (getDepth() == 32)
        {
            getPixels()[i] = color->B;
            getPixels()[i + 1] = color->G;
            getPixels()[i + 2] = color->R;
            getPixels()[i + 3] = color->A;
        }
        if (getDepth() == 24)
        {
            getPixels()[i] = color->B;
            getPixels()[i + 1] = color->G;
            getPixels()[i + 2] = color->R;
        }
        if (getDepth() == 8)
        {
            getPixels()[i] = color->B;
        }
    }
}
